#include "MyFunctions.h"

#ifdef PSP
#include <psputils.h>
#define min(x, y)		(((x) < (y)) ? (x) : (y))
#endif

bool kja_suspend = false;
bool kja_resume = false;

void loadStartupMods();

void loaderInit()
{
	SetupCallbacks();
	oslInit(OSL_IF_USEOWNCALLBACKS);
	oslInitGfx(OSL_PF_5650, 1);
	oslIntraFontInit(INTRAFONT_CACHE_MED);
	
	oslSetQuitOnLoadFailure(true);
	oslSetQuitOnLoadFailureCallback(&osl_onload_fail_callback);
}
int loaderEnd()
{
	oslEndGfx();
	oslQuit();
	return 0;
}
/* Sets up the callback thread and returns its thread id */
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
    osl_quit = 0;
    sceKernelExitGame();
	return 0;
}
/* Power Callback */
int power_callback(int unknown, int pwrflags, void *common)
{
	return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
    int cbid;
    cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
    sceKernelRegisterExitCallback(cbid);
    cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
    scePowerRegisterCallback(0, cbid);
    cbid = sceKernelCreateCallback("Umd Callback",umd_callback,NULL);
    sceUmdRegisterUMDCallBack(cbid);
    
    sceKernelSleepThreadCB();
	return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
    int thid = 0;
    thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
    if (thid >= 0)
	sceKernelStartThread(thid, 0, 0);
    return thid;
}
bool fileExist(string src)
{
	bool r = false;
	ifstream file;
	file.open(src.c_str());
	if(file.is_open())
		r = true;
	else
		r = false;
	file.close();
	return r;
}
bool dirExist(string dir)
{
	DIR *dp;
	dp = opendir(dir.c_str());
	if(dp == NULL)
	{
		closedir(dp);
		return false;
	}
	closedir(dp);
	return true;
}
vector<string> getFileData(const char *_fileloc)
{
	vector<string> data;
	data.clear();
	ifstream file;
	string fileloc, line;
	int loc;
	fileloc = _fileloc;
	file.open(fileloc.c_str());
	while(getline(file,line,'\n'))
	{
		loc = line.find((char) 13,0);
		if(loc != string::npos)
			line.resize(line.size()-1);
		loc = line.find((char)9,0);
		while(loc != string::npos)
		{
			line.replace(loc,1,"     ");
			loc = line.find((char)9,0);
		}
		data.push_back(line);
	}
	file.close();
	if(data.size() < 1) 
		data.push_back("");
	return data;
}
vector<string> getFileDataB(const char *_fileloc)
{
	vector<string> data;
	data.clear();
	ifstream file;
	string fileloc, line;
	int loc;
	fileloc = _fileloc;
	file.open(fileloc.c_str(),ios::in | ios::binary);
	while(getline(file,line,'\n'))
	{
		loc = line.find((char) 13,0);
		if(loc != string::npos)
			line.resize(line.size()-1);
		loc = line.find((char)9,0);
		while(loc != string::npos)
		{
			line.replace(loc,1,"     ");
			loc = line.find((char)9,0);
		}
		data.push_back(line);
	}
	file.close();
	if(data.size() < 1) 
		data.push_back("");
	return data;
}
vector<DirObj> getDirData(const char *_dirloc)
{
	vector<DirObj> r;
	r.clear();
	ArrayList<string> sstr = ArrayList<string>(splitString(_dirloc,'/'));
	if(sstr.contains("ms0:"))
	{
		DIR *d = opendir(_dirloc);
		dirent *dir;
		if(d == NULL)
		{
			closedir(d);
			return r;
		}
		else
		{
			while((dir = readdir(d)) != NULL)
			{
				if(strcmp(dir->d_name,".") != 0 && strcmp(dir->d_name,"..") != 0)
				{
					DirObj dj;
					dj.name = dir->d_name;
					dj.ext = getFileType(dir->d_name);
					if(FIO_SO_ISDIR(dir->d_stat.st_attr) || FIO_S_ISDIR(dir->d_stat.st_mode))
						dj.isDir = true;
					else
						dj.isDir = false;
					dj.absoluteLocation = _dirloc;
					if(_dirloc[strlen(_dirloc)-1] != '/')
						dj.absoluteLocation += "/";
					dj.absoluteLocation += dir->d_name;
					dj.atime = dir->d_stat.st_atime;
					dj.ctime = dir->d_stat.st_ctime;
					dj.mtime = dir->d_stat.st_mtime;
					dj.attr = dir->d_stat.st_attr;
					dj.size = dir->d_stat.st_size;
					r.push_back(dj);
				}
			}
			closedir(d);
		}
	}
	else //sceIoDirent usage
	{
		SceUID fd = sceIoDopen(_dirloc);
		if(fd >= 0)
		{
			SceIoDirent dir;
			while(sceIoDread(fd,&dir) > 0)
			{
				if(strcmp(dir.d_name,".") != 0 && strcmp(dir.d_name,"..") != 0)
				{
					DirObj dj;
					dj.name = dir.d_name;
					dj.ext = getFileType(dir.d_name);
					if(FIO_SO_ISDIR(dir.d_stat.st_attr) || FIO_S_ISDIR(dir.d_stat.st_mode))
						dj.isDir = true;
					else
						dj.isDir = false;
					dj.absoluteLocation = _dirloc;
					if(_dirloc[strlen(_dirloc)-1] != '/')
						dj.absoluteLocation += "/";
					dj.absoluteLocation += dir.d_name;
					dj.atime = dir.d_stat.st_atime;
					dj.ctime = dir.d_stat.st_ctime;
					dj.mtime = dir.d_stat.st_mtime;
					dj.attr = dir.d_stat.st_attr;
					dj.size = dir.d_stat.st_size;
					r.push_back(dj);
				}
			}
		}
	}
	return r;
}
Date getDate()
{
	char *htime = "AM";
	char m[264],day[264],y[264],h[264],min[264],sec[264];
	pspTime time;
	sceRtcGetCurrentClockLocalTime(&time);
	sprintf(day,"%2.2d",time.day);
	sprintf(m,"%2.2d",time.month);
	sprintf(y,"%4.4d",time.year);
	sprintf(min,"%2.2d",time.minutes);
	sprintf(h,"%2.2d",time.hour);
	sprintf(sec,"%2.2d",time.seconds);
	Date d;
	d.hour = h;
	if(stringToInt(h) == 0)
		d.hour = intToString(12);
	else if(stringToInt(h) >= 12)
	{
		htime = "PM";
		d.hour = intToString(stringToInt(h) - 12);
	}		
	d.mday = day;
	d.min = min;
	d.mon = m;
	d.sec = sec;
	d.year = y;
	d.AMPM = htime;
	return d;
}

void saveFileData(const char *_fileloc, vector<string> _data)
{
	ofstream fst;
	fst.open(_fileloc,ios::out);
	for(int i = 0; i < _data.size(); i++)
	{
		fst << (char *)_data.at(i).c_str();
		if(i < _data.size()-1)
			fst << "\n";
	}
	fst.close();
}

bool MF_MAIN_THREAD_RUNNING = false;
bool MF_MAIN_THREAD_SUSPENED = false;
vector<MFTHREAD> MFTHREADS;
void runMF_MAIN_THREAD()
{
	if(!MF_MAIN_THREAD_RUNNING)
	{
		MF_MAIN_THREAD_RUNNING = true;
		MF_MAIN_THREAD_SUSPENED = false;
		while(!osl_quit && !MF_MAIN_THREAD_SUSPENED)
		{
			for(int i = 0; i < MFTHREADS.size() && !osl_quit; i++)
			{
				MFTHREADS.at(i)();
			}
		}
	}
	else
	{
		MF_MAIN_THREAD_RUNNING = false;
		MF_MAIN_THREAD_SUSPENED = true;
	}
}
void Pause(int _delay)
{
	
}
int addFunc(MFTHREAD _thread)
{
	MFTHREADS.push_back(_thread);
	return MFTHREADS.size()-1;
}

SceUID createThread(SceKernelThreadEntry tfunc,char *tname)
{
	 SceUID thid;
	 thid = sceKernelCreateThread(tname, tfunc,0x20, (256 * 2) * 1024, PSP_THREAD_ATTR_USER, NULL);
	 if(thid >= 0)
		 sceKernelStartThread(thid,0,0);
	 return thid;
}

int keylistCmp(OSL_KEYLIST k1, OSL_KEYLIST k2)
{
	int r = 0;
	if(k1.up != k2.up) r = 1;
	if(k1.down != k2.down) r = 1;
	if(k1.left != k2.left) r = 1;
	if(k1.right != k2.right) r = 1;
	if(k1.select != k2.select) r = 1;
	if(k1.start != k2.start) r = 1;
	if(k1.R != k2.R) r = 1;
	if(k1.L != k2.L) r = 1;
	if(k1.triangle != k2.triangle) r = 1;
	if(k1.circle != k2.circle) r = 1;
	if(k1.cross != k2.cross) r = 1;
	if(k1.square != k2.square) r = 1;
	if(k1.hold != k2.hold) r = 1;
	if(k1.home != k2.home) r = 1;
	return r;
}


SceUID load_module(const char *path, int flags, int type)
{
	SceKernelLMOption option;
	SceUID mpid;

	/* If the type is 0, then load the module in the kernel partition, otherwise load it
	   in the user partition. */
	if (type == 0) {
		mpid = 1;
	} else {
		mpid = 2;
	}

	memset(&option, 0, sizeof(option));
	option.size = sizeof(option);
	option.mpidtext = mpid;
	option.mpiddata = mpid;
	option.position = 0;
	option.access = 1;
	return sceKernelLoadModule(path, flags, type > 0 ? &option : NULL);
}
void osl_onload_fail_callback(const char *filename,u32 reserved)
{
	oslDebug("filename failed to load \n%s",filename);
}
bool umd_in_drive = false;
int umd_callback(int arg1, int arg2, void *arg)
{
	if(umd_in() && sceUmdCheckMedium() == 0)
	{
		umd_in_drive = false;
		sceUmdDeactivate(1,"disc0:");
	}
	else if(!umd_in() && sceUmdCheckMedium() != 0)
	{
		umd_in_drive = true;
		sceUmdActivate(1, "disc0:");
	}
	return 0;
}
bool umd_in()
{
	return umd_in_drive;
}
